package com.minelx.sqlstructures.core.database;

import com.minelx.sqlstructures.core.table.ITable;
import com.minelx.sqlstructures.core.table.MysqlTable;
import com.minelx.sqlstructures.core.values.FieldValues;
import com.minelx.sqlstructures.statements.CreateTableStatement;

import javax.sql.DataSource;
import javax.swing.*;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import static java.lang.String.format;

public class MysqlDatabase implements IDatabase {

	private final DataSource dataSource;

	private final String databaseName;

	public MysqlDatabase(DataSource dataSource, String databaseName) {
		this.dataSource = dataSource;
		this.databaseName = databaseName;
	}

	@Override
	public MysqlTable table(String tableName) {
		return new MysqlTable(dataSource, databaseName, tableName);
	}

	@Override
	public ITable createTable(String tableName, List<FieldValues> fields) {
		CreateTableStatement result = new CreateTableStatement(databaseName + "." + tableName);
		result.ifNotExists();
		result.appendAll(fields);
		execute(dataSource, result.toSql());
		return table(tableName);
	}

	@Override
	public List<ITable> getTables() {
		try (Connection connection = dataSource.getConnection();
		     Statement statement = connection.createStatement()) {
			ResultSet resultSet = statement.executeQuery(format("select table_name from information_schema.tables where table_schema='%s'", databaseName));
			List<ITable> result = new LinkedList<>();
			while (resultSet.next()) {
				String tableName = resultSet.getString("TABLE_NAME");
				result.add(table(tableName));
			}
			return result;
		} catch (SQLException e) {
			throw new RuntimeException("something is wrong here", e);
		}
	}

	@Override
	public String getName() {
		return databaseName;
	}

	@Override
	public void clear() {
		clearSafetyNet(databaseName);
		try (Connection connection = dataSource.getConnection();
		     Statement statement = connection.createStatement()) {
			statement.execute("drop database " + databaseName);
			statement.execute("create database " + databaseName);
		} catch (SQLException e) {
			throw new RuntimeException("something is wrong here", e);
		}
	}

	private void execute(DataSource dataSource, String sql) {
		try (Connection connection = dataSource.getConnection();
		     Statement statement = connection.createStatement()) {
			statement.execute(sql);
		} catch (SQLException e) {
			throw new RuntimeException("something is wrong here", e);
		}
	}

	public static void clearSafetyNet(String databaseName) {
		if (notTestedDatabase(databaseName)) {
			JOptionPane.showConfirmDialog(null, "you are clearing: " + databaseName);
			JOptionPane.showConfirmDialog(null, "you are clearing: " + databaseName);
			JOptionPane.showConfirmDialog(null, "you are clearing: " + databaseName);
			JOptionPane.showConfirmDialog(null, "you are clearing: " + databaseName);
			JOptionPane.showConfirmDialog(null, "you are clearing: " + databaseName);
			throw new UnsupportedOperationException("MysqlDatabase.clear is not supported.");
		}
	}

	private static boolean notTestedDatabase(String databaseName) {
		return !databaseName.startsWith("testdb");
	}
}
